/*
 * @lc app=leetcode.cn id=79 lang=cpp
 *
 * [79] 单词搜索
 *
 * https://leetcode.cn/problems/word-search/description/
 *
 * algorithms
 * Medium (46.34%)
 * Likes:    1334
 * Dislikes: 0
 * Total Accepted:    326.8K
 * Total Submissions: 704.9K
 * Testcase Example:  '[["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]]\n"ABCCED"'
 *
 * 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中，返回 true ；否则，返回 false
 * 。
 *
 * 单词必须按照字母顺序，通过相邻的单元格内的字母构成，其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
 *
 *
 *
 * 示例 1：
 *
 *
 * 输入：board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word =
 * "ABCCED"
 * 输出：true
 *
 *
 * 示例 2：
 *
 *
 * 输入：board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word =
 * "SEE"
 * 输出：true
 *
 *
 * 示例 3：
 *
 *
 * 输入：board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word =
 * "ABCB"
 * 输出：false
 *
 *
 *
 *
 * 提示：
 *
 *
 * m == board.length
 * n = board[i].length
 * 1
 * 1
 * board 和 word 仅由大小写英文字母组成
 *
 *
 *
 *
 * 进阶：你可以使用搜索剪枝的技术来优化解决方案，使其在 board 更大的情况下可以更快解决问题？
 *
 */

// @lc code=start
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
    vector<int> direction{-1, 0, 1, 0, -1};
    bool exist(vector<vector<char>> &board, string word) {
        if (board.empty()) {
            return false;
        }
        int m = board.size();
        int n = board[0].size();
        vector<vector<bool>> visited(m, vector<bool>(n, false));
        bool find = false;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                backtracking(i, j, board, word, find, visited, 0);
            }
        }
        return find;
    }

    // 辅函数
    void backtracking(int i, int j, vector<vector<char>> &board, string &word, bool &find, vector<vector<bool>> &visited, int pos) {
        if (i < 0 || i >= (int)board.size() || j < 0 || j >= (int)board[0].size()) {
            return;
        }
        if (visited[i][j] || find || board[i][j] != word[pos]) {
            return;
        }
        if (pos == (int)word.size() - 1) {
            find = true;
            return;
        }
        // 修改当前节点
        visited[i][j] = true;
        // 递归子节点
        for (int z = 0; z < 4; ++z) {
            int x = i + direction[z];
            int y = j + direction[z + 1];
            backtracking(x, y, board, word, find, visited, pos + 1);
        }
        // 回改当前节点状态
        visited[i][j] = false;
    }
};
// @lc code=end
